import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router';

/**
 * https://zhuanlan.zhihu.com/p/29823560
 * shouldDetach 是否允许复用路由
 * store 当路由离开时会触发，存储路由
 * shouldAttach 是否允许还原路由
 * retrieve 获取存储路由
 * shouldReuseRoute 进入路由触发，是否同一路由时复用路由，返回true时则不会跳转页面
 */
export class RouteStrategyService implements RouteReuseStrategy {

  private ignoreRouters: Array<string> = ['/login', '/layout']

  public static handlers: { [key: string]: DetachedRouteHandle } = {};

  /**
   * 删除某路由的缓存
   */
  public static deleteRouteSnapshot(path: string): void {
    const name = path
    if (RouteStrategyService.handlers[name]) {
      delete RouteStrategyService.handlers[name];
    }
  }
  /**
   * shouldReuseRoute()
   * 决定是否复用路由，根据切换的future curr的节点层级依次调用，
   * 返回值为true时表示当前节点层级路由复用，然后继续下一路由节点调用，入参为切换的下一级路由（子级）的future curr路由的节点，
   * 返回值为false时表示不在复用路由，并且不再继续调用此方法（future路由不再复用，其子级路由也不会复用，所以不需要再询问下去），
   * root路由节点调用一次，非root路由节点调用两次这个方法，第一次比较父级节点，第二次比较当前节点，
   */
  public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig && JSON.stringify(future.params) === JSON.stringify(curr.params);
  }

  /**
  * retrieve()
  * 接上一步骤，当当前层级路由不需要复用的时候，调用一下retrieve方法，
  * 其子级路由也会调用一下retrieve方法，如果返回的是null，那么当前路由对应的组件会实例化，这种行为一直持续到末级路由。
  */
  public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    let path = this.getPath(route);
    const isIgnorePath = this.ignoreRouters.some(p => path === p);
    if (isIgnorePath) {
      console.log('%c 忽略了：%s', 'color:red', path);
      return null
    }


    return RouteStrategyService.handlers[this.getPath(route)] || null;
  }

  /**
   * shouldDetach()
   * 是对上一路由的数据是否实现拆离，其调用开始是当前层级路由不需要复用的时候，
   * 即shouldReuseRoute()返回false的时候，如果这时候反回false，将继续到上一路由的下一层级调用shouldDetach,
   * 直到返回true或者是最末级路由后才结束对shouldDetach的调用，当返回true时就调用一次store 方法，请看下一步骤
   */
  public shouldDetach(route: ActivatedRouteSnapshot): boolean {
    console.log('%c SETP 02', 'color:green');
    return true;
  }

  /**
   * 将路由写入缓存
   * 在这里具体实现如何缓存 RouteHandle
   * 提供了我们离开的路由和 RouteHandle
   * @param {ActivatedRouteSnapshot} route
   * @param {DetachedRouteHandle} detachedTree
   * @memberof CacheRouteReuseStrategy
   */
  public store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {
    RouteStrategyService.handlers[this.getPath(route)] = detachedTree;
  }

  /**
   * 路由被导航 如果此方法返回 true 则触发 retrieve 方法
   * 如果返回 false 这个组件将会被重新创建
   * @param {ActivatedRouteSnapshot} route
   * @returns {boolean}
   * @memberof CacheRouteReuseStrategy
   */
  public shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return !!RouteStrategyService.handlers[this.getPath(route)];
  }

  // 用路由地址作为缓存键
  private getPath(route: ActivatedRouteSnapshot): string {
    let r: any = route;
    let p: string = r["_routerState"].url;
    return p;
  }
}